"""
Copyright (c) 2012, 2013 Regents of the University of California
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions 
are met:

 - Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
 - Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the
   distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
OF THE POSSIBILITY OF SUCH DAMAGE.
"""

from models import *
from django.forms import ModelForm
from django import forms
from django.db.models import Q
from olwidget.forms import MapModelForm
from olwidget.fields import MapField, EditableLayerField, InfoLayerField
from olwidget.widgets import InfoMap

def make_zoneForm(projectId, formData):
    class zoneForm(ModelForm):
        if projectId:
            project = forms.ModelChoiceField(queryset=Project.objects.filter(id=projectId), empty_label=None)
        class Meta:
            model = Zone
    if formData:
        return zoneForm(formData)
    else:
        return zoneForm

def make_zoneFormInstance(formData, zoneInstanceId, zonea, projectId, floorId=False, zone_categories=[]):
    if zoneInstanceId:
        a = Zone.objects.get(pk=zoneInstanceId)
        if len(zone_categories) < 4:
            current_zones = Zone.objects.filter(project=projectId, floor=a.floor, zone_category__pmp_category__in=zone_categories).exclude(pk=zoneInstanceId)
        else:
            current_zones = Zone.objects.filter(project=projectId, floor=a.floor).exclude(pk=zoneInstanceId)
        try:
            map_obj = Map.objects.get(project=projectId, floor=a.floor)
        except:
            map_obj = Map.objects.filter(project=projectId)[0]
    elif floorId:
        if len(zone_categories) < 4:
            current_zones = Zone.objects.filter(project=projectId, floor=Floor.objects.get(pk=floorId), zone_category__pmp_category__in=zone_categories)
        else:
            current_zones = Zone.objects.filter(project=projectId, floor=Floor.objects.get(pk=floorId))
        try:
            map_obj = Map.objects.get(project=projectId, floor=Floor.objects.get(pk=floorId))
        except:
            map_obj = Map.objects.filter(project=projectId)[0]
    else:
        map_obj = Map.objects.filter(project=projectId)[0]
        if len(zone_categories) < 4:
            current_zones = Zone.objects.filter(project=projectId, floor=Project.objects.get(pk=projectId).floors.all()[0], zone_category__pmp_category__in=zone_categories)
        else:
            current_zones = Zone.objects.filter(project=projectId, floor=Project.objects.get(pk=projectId).floors.all()[0])
    info = []
    for zone in current_zones:
        info.append((zone.zone_map, {
            'html': 'Zone: ' + zone.name,
            'style': {
                'fill_color': 'green',
                'stroke_color': 'green',
                'stroke_opacity': 0.7,
                'stroke_width': 1,
                'fill_opacity': 0.15,
            },
        }))
    class zoneFormInstance(MapModelForm):
        floor = forms.ModelChoiceField(queryset=Project.objects.get(pk=projectId).floors.all(),empty_label=None) 
        # set options for individual geometry fields by explicitly declaring the
        # field type.  If not declared, defaults will be used.
        zone_map = EditableLayerField({
            'geometry': 'polygon',
            'overlay_style': {
                'fill_opacity': 0.2,
            }})
        other_zones =  InfoLayerField(info)
        #thermostats = EditableLayerField({
        #    'geometry': 'point',
        #    'isCollection': 'true',
        #    'overlay_style': {
        #        'stroke_color': 'green',
        #        'fill_color': 'green',
        #    }})
        class Meta:
            model = Zone
            exclude = ('project')
            maps = (
                (('zone_map', 'other_zones'), {
                    'default_zoom': 2,
                    'default_lat': 1,
                    'layers': ['image_layer'],
                    'mapOptions':({
                        'max_extent': [map_obj.left_extent,map_obj.bottom_extent,map_obj.right_extent,map_obj.top_extent],
                        'max_resolution': map_obj.resolution,
                        'num_zoom_levels': map_obj.zoom_levels,
                        }),
                }),
            )
    if zoneInstanceId:
        a = Zone.objects.get(pk=zoneInstanceId)
        if formData:
            return zoneFormInstance(formData, instance=a)
        else:
            return zoneFormInstance(instance=a)
    elif formData and zoneInstanceId == "" and zonea:
        return zoneFormInstance(formData, instance=zonea)
    elif formData and zoneInstanceId == "":
        return zoneFormInstance(formData)
    else:
        return zoneFormInstance
    
def make_zoneFD(projectId, formData, newzonea):
    class zoneFD(ModelForm):
        name = forms.ModelChoiceField(queryset=Zone.objects.filter(project=projectId).order_by('name'))
        class Meta:
            model = Zone
            fields = ('name',)
    if newzonea:
        return zoneFD(initial = {'name':newzonea.name}, auto_id="id_zoneInstance_%s")
    elif formData:
        return zoneFD(formData, auto_id="id_zoneInstance_%s")
    else:
        return zoneFD(auto_id="id_zoneInstance_%s")

def make_mapFD(projectId, formData, newmapa):
    class mapFD(ModelForm):
        name = forms.ModelChoiceField(queryset=Map.objects.filter(project=projectId))
        class Meta:
            model = Map
            fields = ('name',)
    if newmapa:
        return mapFD(initial = {'name':newmapa}, auto_id="id_mapInstance_%s")
    elif formData:
        return mapFD(formData, auto_id="id_mapInstance_%s")
    else:
        return mapFD(auto_id="id_mapInstance_%s")

def make_mapFormInstance(formData, mapInstanceId, mapa, projectId, filesData=False):
    class mapFormInstance(ModelForm):
        floor = forms.ModelChoiceField(queryset=Project.objects.get(pk=projectId).floors.all(),empty_label=None)
        class Meta:
            model = Map
            exclude = ('project')

    if mapInstanceId:
        a = Map.objects.get(pk=mapInstanceId)
        if formData:
            return mapFormInstance(formData, filesData, instance=a)
        else:
            return mapFormInstance(instance=a)
    elif formData and mapInstanceId == "" and mapa:
        return mapFormInstance(formData, filesData, instance=mapa)
    elif mapa:
        return mapFormInstance(instance=mapa)
    elif formData and mapInstanceId == "":
        return mapFormInstance(formData, filesData)
    else:
        return mapFormInstance

class ChartImageForm(ModelForm):
    class Meta:
        model = ChartImage
        exclude = ('project','image_url','pmp_category', 'type', 'legend')

class ConfigFileFormDrop(ModelForm):
    name = forms.ModelChoiceField(queryset=ConfigFile.objects.all())
    class Meta:
        model = ConfigFile
        fields = ('name',)

class ConfigFileForm(ModelForm):
    class Meta:
        model = ConfigFile
        fields = ('name',)


class IeqModelDef(ModelForm):
    class Meta:
        model = IeqSpace
        exclude = ('model')
        
def make_IeqSpaceFD(modelId, formData, newStA):
    class IeqSpaceFD(ModelForm):
        space_type = forms.ModelChoiceField(queryset=IeqSpace.objects.filter(model=modelId))
        class Meta:
            model = IeqSpace
            fields = ('space_type',)
    if newStA:
        return IeqSpaceFD(instance = newStA, auto_id="id_stFD_%s")
    elif formData:
        return IeqSpaceFD(formData, auto_id="id_stFD_%s")
    else:
        return IeqSpaceFD(auto_id="id_stFD_%s")

class IeqModelFD(ModelForm): #same as below except with empty label
    name = forms.ModelChoiceField(queryset=IeqModel.objects.all())
    class Meta:
        model = IeqModel
        fields = ('name',)

def make_modelForm(formData):
    class IeqModelForm(ModelForm):
        class Meta:
            model = IeqModel
    if formData:
        return IeqModelForm(formData)
    else:
        return IeqModelForm

class IeqModelFormDrop(ModelForm):
    name = forms.ModelChoiceField(queryset=IeqModel.objects.all(), empty_label=None, initial=IeqModel.objects.get(pk=4).id)
    class Meta:
        model = IeqModel
        fields = ('name',)

#not used right now
#def make_ieqData_formd(modelId, category, projectId):
#    class IeqDataFormDrop(ModelForm):
#        name = forms.ModelChoiceField(queryset=IeqData.objects.filter(ieq_category=category,ieq_space__model=modelId,project=projectId), widget=forms.Select(attrs={'onchange':''}))
#        class Meta:
#            model = IeqData
#            fields = ('name',)
#    return IeqDataFormDrop(auto_id="id_ieqData_%s")

def make_project_form(groupL):
    class ProjectForm(ModelForm): #project form for the project drop down on most pages
        query = ['Project.objects.filter(']
        for i in xrange(len(groupL)):
            if i + 1 < len(groupL):
                query.append('Q(group=%i) | ' % groupL[i])
            else:
                query.append('Q(group=%i))' % groupL[i])
        query = ''.join(query)
        queryset_n = eval(query)
        name = forms.ModelChoiceField(queryset = queryset_n, empty_label=None)    
        class Meta:
            model = Project
            fields = ('name',)
    return ProjectForm

def make_project_formd(groupL):
    class ProjectFormD(ModelForm): #project form for the project drop down on the project page
        query = ['Project.objects.filter(']
        for i in xrange(len(groupL)):
            if i + 1 < len(groupL):
                query.append('Q(group=%i) | ' % groupL[i])
            else:
                query.append('Q(group=%i))' % groupL[i])
        query = ''.join(query)
        queryset_n = eval(query)
        name = forms.ModelChoiceField(queryset = queryset_n)
        class Meta:
            model = Project
            fields = ('name',)
    return ProjectFormD

class ProjectFormU(ModelForm): #project form for the actual project page form
    class Meta:
        model = Project
        exclude = ('survey_tc','survey_iaq','survey_lighting','survey_acoustics')

class ProjectSurveyForm(ModelForm): #project survey form fields
    class Meta:
        model = Project
        fields = ('survey_tc','survey_iaq','survey_lighting','survey_acoustics','survey_tc_bm','survey_iaq_bm','survey_lighting_bm','survey_acoustics_bm')

def make_sensor_form(project):
    class SensorForm(ModelForm):
        class Meta:
            model = Sensor
    return SensorForm

def make_deviceInstance_form(deviceInstanceId, formData, devicea, projectId, floorId=False):
    if deviceInstanceId:
        a = Test.objects.get(pk=deviceInstanceId)
        try:
            map_obj = Map.objects.get(project=projectId, floor=a.floor)
        except:
            map_obj = Map.objects.filter(project=projectId)[0]
    elif floorId:
        try:
            map_obj = Map.objects.get(project=projectId, floor=Floor.objects.get(pk=floorId))
        except:
            map_obj = Map.objects.filter(project=projectId)[0]
    else:
        map_obj = Map.objects.filter(project=projectId)[0]
    class deviceInstanceForm(MapModelForm):
        floor = forms.ModelChoiceField(queryset=Project.objects.get(pk=projectId).floors.all(),empty_label=None)
        class Meta:
            model = Test
            exclude = ('device','project') #zone is not shown, but needs to be included in order to set it
            options = {
                    'default_zoom': 2,
                    'default_lat': 1,
                    'layers': ['image_layer'],
                    'mapOptions':({
                        'max_extent': [map_obj.left_extent,map_obj.bottom_extent,map_obj.right_extent,map_obj.top_extent],
                        'max_resolution': map_obj.resolution,
                        'num_zoom_levels': map_obj.zoom_levels,
                        }),
                          'overlay_style': {
                                'stroke_color': 'red',
                                'fill_color': 'red'
                        }
                }
    if deviceInstanceId:
        a = Test.objects.get(pk=deviceInstanceId)
        if formData:
            return deviceInstanceForm(formData, instance=a)
        else:
            return deviceInstanceForm(instance=a)
    elif formData and deviceInstanceId == "" and devicea: #submit from a new form
        return deviceInstanceForm(formData, instance=devicea)
    elif formData and deviceInstanceId == "": #change floor
        return deviceInstanceForm(formData)
    else:
        return deviceInstanceForm

class HdrTestForm(ModelForm):
    class Meta:
        model = HdrTest
        exclude = ('test')

class AcousticsTestForm(ModelForm):
    class Meta:
        model = AcousticsTest
        exclude = ('test')

class IaqTestForm(ModelForm):
    class Meta:
        model = IaqTest
        exclude = ('test')
        
def make_manualEntry_form(deviceId, deviceInstanceId=False):
    device_obj = Device.objects.get(pk=deviceId)
    if deviceInstanceId != False and deviceInstanceId != '':
        test_obj = Test.objects.get(pk=deviceInstanceId)
    else:
        test_obj = False
    if device_obj.name == 'HDR camera':
        if test_obj:
            try:
                b = HdrTest.objects.get(test=test_obj)
                manualEntryF = HdrTestForm(instance=b)
            except:
                manualEntryF = HdrTestForm()
        else:
            manualEntryF = HdrTestForm()
    elif device_obj.name == 'IAQ meter':
        if test_obj:
            try:
                b = IaqTest.objects.get(test=test_obj)
                manualEntryF = IaqTestForm(instance=b)
            except:
                manualEntryF = IaqTestForm()
        else:
            manualEntryF = IaqTestForm()
    elif device_obj.name == 'Sound level meter':
        if test_obj:
            try:
                b = AcousticsTest.objects.get(test=test_obj)
                manualEntryF = AcousticsTestForm(instance=b)
            except:
                manualEntryF = AcousticsTestForm()
        else:
            manualEntryF = AcousticsTestForm()
    else:
        manualEntryF = False
    return manualEntryF

def make_deviceIFD(projectId, deviceId, formData, newdevicea):
    class deviceInstanceFormD(ModelForm):
        if deviceId:
            #id = forms.ModelChoiceField(queryset=Test.objects.filter(device=deviceId, project=projectId).distinct().order_by('id'))
            id = forms.ModelChoiceField(queryset=Test.objects.filter(device=deviceId, project=projectId).distinct().order_by('id'))
        class Meta:
            model = Test
            fields = ('id',)
    if newdevicea:
        return deviceInstanceFormD(instance = newdevicea, auto_id="id_deviceInstance_%s")
    elif formData:
        return deviceInstanceFormD(formData, auto_id="id_deviceInstance_%s")
    else:
        return deviceInstanceFormD(auto_id="id_deviceInstance_%s")

def make_deviceFD(projectId, formData):
    class deviceFormD(ModelForm):
        name = forms.ModelChoiceField(queryset=Device.objects.filter(sensor__project=projectId).distinct().order_by('name'))
        class Meta:
            model = Device
            fields = ('name',)
    if formData:
        return deviceFormD(formData, auto_id='id_device_%s')
    else:
        return deviceFormD(auto_id='id_device_%s')

def make_floorForm(projectId=5):
    class floorForm(ModelForm):
        floor = forms.ModelChoiceField(queryset=Project.objects.get(pk=projectId).floors.all(),empty_label=None) #empty_label=None  isn't working for zone/device instances
        class Meta:
            model = Floor
    return floorForm
